package edu.tfh.s2.ehkbot.simulation;

import edu.tfh.s2.ehkbot.EHKBotMain;
import edu.tfh.s2.ehkbot.daten.Protokoll;
import edu.tfh.s2.ehkbot.gerete.sensoren.IndoorGPS;
import edu.tfh.s2.ehkbot.steuerung.Karte;
import edu.tfh.s2.ehkbot.steuerung.Position;
import edu.tfh.s2.ehkbot.util.Observer;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.NoSuchElementException;
import java.util.Vector;

/**
 * RoutingGUI stellt die Karte und das Routing da.
 * @author s2zehn
 *
 */
public class RoutingGUI extends JFrame implements Observer {

	/**
	 * Speichert Bilder für die Objekte
	 *
	 */
	private static class Pic {
		private static ImageIcon blank = new ImageIcon("blank.PNG");
		private static ImageIcon block = new ImageIcon("block.PNG");
		private static ImageIcon free = new ImageIcon("free.PNG");
		private static final int height = 10;
		private static ImageIcon nord = new ImageIcon("nord.PNG");

		private static ImageIcon ost = new ImageIcon("ost.PNG");
		private static ImageIcon start = new ImageIcon("start.PNG");
		private static ImageIcon sued = new ImageIcon("sued.PNG");
		private static ImageIcon west = new ImageIcon("west.PNG");

		private static final int width = 10;
		private static ImageIcon ziel = new ImageIcon("ziel.PNG");
	}

	private static RoutingGUI instance = null;
	private static JPanel jMapPanel = null;
	private static final long serialVersionUID = 1L;

	public static RoutingGUI getInstance() {
		if (instance == null) {
			instance = new RoutingGUI();
			instance.setTitle("EHKBot RoutingGUI View");
		}
		return instance;
	}

	private BufferedImage buffer = null;
	private JPanel jContentPane = null;

	private JPanel jMenuPanel = null;

	private JSplitPane jSplitPane = null;

	private Vector<Position> lastRoute = null;

	private RoutingGUI() {
		super();
		initialize();
		this.addWindowListener(new WindowAdapter() {
			  public void windowClosing(WindowEvent evt) {
			    SimulationGUI.getInstance().getZeigeRoutingGUIButton().setSelected(false);
			  }
		});
	}
	
	@Override
	public void dispose(){
		System.err.println("test");
		super.dispose();
	}

	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			BoxLayout jContentPaneLayout = new BoxLayout(jContentPane, javax.swing.BoxLayout.X_AXIS);
			jContentPane.setLayout(jContentPaneLayout);
			jContentPane.add(getJSplitPane(), null);
		}
		return jContentPane;
	}

	private JPanel getJMapPanel() {
		if (jMapPanel == null) {
			jMapPanel = new JPanel() {
				private static final long serialVersionUID = 1L;

				public void paint(Graphics g) {
					g.drawImage(buffer, 0, 0, null);
				}
			};
			jMapPanel.setLayout(null);
		}
		return jMapPanel;
	}

	private JPanel getJMenuPanel() {
		if (jMenuPanel == null) {
			jMenuPanel = new JPanel();
			jMenuPanel.setLayout(new BoxLayout(getJMenuPanel(), BoxLayout.Y_AXIS));
		}
		return jMenuPanel;
	}

	private JSplitPane getJSplitPane() {
		if (jSplitPane == null) {
			jSplitPane = new JSplitPane();
			jSplitPane.setEnabled(true);
			jSplitPane.setContinuousLayout(false);
			jSplitPane.setLeftComponent(getJMenuPanel());
			jSplitPane.setRightComponent(getJMapPanel());
		}
		return jSplitPane;
	}

	private void initialize() {
		this.setContentPane(getJContentPane());
		this.setTitle("RoutingGUI");
		this.setBounds(new Rectangle(0, 0, 900, 500));
		buffer = new BufferedImage(900, 500, BufferedImage.TYPE_INT_RGB);
	}

	public void refreshMapPanel() {
		refreshMapPanel(buffer.getGraphics(), EHKBotMain.getInstance().getKarte());
		getJMapPanel().repaint();

	}

	/**
	 * Aktualiesiert die Anzeige der Karte.
	 * @param g Ein Graphics Objekt in den gezeichnet wird.
	 * @param karte Die Karte.
	 */
	public void refreshMapPanel(Graphics g, Karte karte) {
		for (int y = 0; y < karte.getYSize(); y += Karte.quantiesierung) {
			for (int x = 0; x < karte.getXSize(); x += Karte.quantiesierung) {
				Position pos = new Position(x, y, 0);
				Karte.Toplogie topo = karte.getTopologie(pos);
				if (topo == Karte.Toplogie.FAHRBEREICH)
					showPic(g, Color.WHITE, pos, 10, 10);
				else
					showPic(g, Color.GRAY, pos, 10, 10);
			}
		}
	}

	/**
	 * Plaziert ein Rechteck auf der Karte
	 * @param g Das Graphics Objekt in den gezeichnet wird.
	 * @param c Die Farbe.
	 * @param pos Die Position.
	 * @param picWidth Die Breite in Pixel.
	 * @param picHeight Die Höhe in Pixel.
	 */
	private void showPic(Graphics g, Color c, Position pos, int picWidth, int picHeight) {
		g.setColor(c);
		g.fillRect(pos.getX() / 1000 * picHeight, pos.getY() / 1000 * picWidth, picHeight, picWidth);
	}

	/**
	 * Plaziert ein Bild auf der Karte
	 * @param g Das Graphics Objekt in den gezeichnet wird.
	 * @param icon Das Bild.
	 * @param pos Die Position.
	 * @param picWidth Die Breite in Pixel.
	 * @param picHeight Die Höhe in Pixel.
	 */
	private void showPic(Graphics g, ImageIcon icon, Position pos, int picWidth, int picHeight) {
		g.drawImage(icon.getImage(), pos.getX() / 1000 * picHeight, pos.getY() / 1000 * picWidth, null);
	}

	/**
	 * Zeitgt den Weg des Bot an. 
	 * @param way Die Wegepunkte.
	 */
	@SuppressWarnings("unchecked")
	public void showRoute(Vector<Position> way) {
		lastRoute = (Vector<Position>) way.clone();
		refreshMapPanel(buffer.getGraphics(), EHKBotMain.getInstance().getKarte());
		showRoute(way, buffer.getGraphics(), EHKBotMain.getInstance().getKarte());
		getJMapPanel().repaint();
	}

	/**
	 * Zeichnet den Weg in das Graphics Objekt.
	 * @param way Die Wegepunkte.
	 * @param g Das Graphics Objekt in den gezeichnet wird.
	 * @param karte Die Karte
	 */
	@SuppressWarnings("unchecked")
	public void showRoute(Vector<Position> way, Graphics g, Karte karte){
		lastRoute = (Vector<Position>) way.clone();
		try {
			Position startPosition = way.firstElement();
			Position endPosition = way.lastElement();

			showPic(g, Pic.start, startPosition, Pic.width, Pic.height);
			showPic(g, Pic.ziel, endPosition, Pic.width, Pic.height);
			for (int i = 1; i < way.size() - 1; ++i) {
				Position last = way.get(i - 1);
				Position now = way.get(i);

				ImageIcon pfeil = slectRichtungPic(last, now);

				showPic(g, pfeil, now, Pic.width, Pic.height);

			}
		} catch (NoSuchElementException e) {
			Protokoll.getInstanc().exception(e);
		}
	}

	/**
	 * Gibt das passende Icon zurück für eine Richtung, die sich aus den Positionen ergibt. 
	 * @param last Die Position aktuell.
	 * @param now Die Position später.
	 * @return Das passende Icon.
	 */
	private ImageIcon slectRichtungPic(Position last, Position now) {
		int diffX = last.getX() - now.getX();
		int diffY = last.getY() - now.getY();
		if (diffX == 0) {
			if (diffY < 0)
				return Pic.sued;
			else
				return Pic.nord;
		} else {
			if (diffX < 0)
				return Pic.ost;
			else
				return Pic.west;
		}
	}

	/**
	 * @see edu.tfh.s2.ehkbot.util.Observer#update()
	 */
	@Override
	public void update() {
		/*
		 * RoutingGUI ist Beobachter von IndoorGPS.
		 * Wenn IndoorGPS ein update abfeuert, wird die Karte neu gezeichnet.
		 */
		if (lastRoute != null) {
			showRoute(lastRoute);
		}
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			Protokoll.getInstanc().exception(e);
		}
	}

}
